#include "QQZipApi.h"

bool QQZipApi::compressFile(const QString& filename, const QString& target)
{
	qInfo() << "Starting compression of file:" << filename << "to target:" << target;

	zip_t* zipFile = zip_open(target.toStdString().c_str(), ZIP_CREATE, nullptr);
	if (!zipFile) {
		qWarning() << "Failed to create or open zip file:" << target;
		return false;
	}

	zip_source_t* source = zip_source_file(zipFile, filename.toStdString().c_str(), 0, 0);
	if (!source) {
		qWarning() << "Failed to create source for file:" << filename;
		zip_close(zipFile);
		return false;
	}

	zip_int64_t index = zip_file_add(zipFile, QFileInfo(filename).fileName().toStdString().c_str(), source, ZIP_FL_OVERWRITE);
	if (index == -1) {
		qWarning() << "Failed to add file to zip:" << filename;
		zip_close(zipFile);
		return false;
	}

	zip_close(zipFile);
	qInfo() << "Successfully compressed file:" << filename << "to" << target;
	return true;
}

bool QQZipApi::compressDir(const QString& dirname, const QString& target)
{
	qInfo() << "Starting compression of directory:" << dirname << "to target:" << target;

	QDir dir(dirname);
	QFileInfoList files = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
	zip_t* zipFile = zip_open(target.toStdString().c_str(), ZIP_CREATE, nullptr);
	if (!zipFile) {
		qWarning() << "Failed to create or open zip file:" << target;
		return false;
	}

	foreach(const QFileInfo & fileInfo, files) {
		zip_source_t* source = zip_source_file(zipFile, fileInfo.absoluteFilePath().toStdString().c_str(), 0, 0);
		if (!source) {
			qWarning() << "Failed to create source for file:" << fileInfo.absoluteFilePath();
			zip_close(zipFile);
			return false;
		}

		zip_int64_t index = zip_file_add(zipFile, fileInfo.fileName().toStdString().c_str(), source, ZIP_FL_OVERWRITE);
		if (index == -1) {
			qWarning() << "Failed to add file to zip:" << fileInfo.absoluteFilePath();
			zip_close(zipFile);
			return false;
		}
	}

	zip_close(zipFile);
	qInfo() << "Successfully compressed directory:" << dirname << "to" << target;
	return true;
}

bool QQZipApi::decompressFile(const QString& filename, const QString& target)
{
	qInfo() << "Starting decompression of file:" << filename << "to target:" << target;

	zip_t* zipFile = zip_open(filename.toStdString().c_str(), ZIP_RDONLY, nullptr);
	if (!zipFile) {
		qWarning() << "Failed to open zip file for reading:" << filename;
		return false;
	}

	zip_int64_t numEntries = zip_get_num_entries(zipFile, 0);
	if (numEntries == 0) {
		qWarning() << "No entries found in zip file:" << filename;
		zip_close(zipFile);
		return false;
	}

	zip_file_t* file = zip_fopen_index(zipFile, 0, 0);
	if (!file) {
		qWarning() << "Failed to open first entry in zip file:" << filename;
		zip_close(zipFile);
		return false;
	}

	QFile dest(target);
	if (!dest.open(QIODevice::WriteOnly)) {
		qWarning() << "Failed to open target file for writing:" << target;
		zip_fclose(file);
		zip_close(zipFile);
		return false;
	}

	char buffer[ZIP_FILE_CACHE_SIZE];
	int bytesRead = 0;
	while ((bytesRead = zip_fread(file, buffer, ZIP_FILE_CACHE_SIZE)) > 0) {
		dest.write(buffer, bytesRead);
	}

	dest.close();
	zip_fclose(file);
	zip_close(zipFile);

	qInfo() << "Successfully decompressed file:" << filename << "to" << target;
	return true;
}

bool QQZipApi::decompressDir(const QString& filename, const QString& target)
{
	qInfo() << "Starting decompression of directory from:" << filename << "to target directory:" << target;

	zip_t* zipFile = zip_open(filename.toStdString().c_str(), ZIP_RDONLY, nullptr);
	if (!zipFile) {
		qWarning() << "Failed to open zip file for reading:" << filename;
		return false;
	}

	zip_int64_t numEntries = zip_get_num_entries(zipFile, 0);
	if (numEntries == 0) {
		qWarning() << "No entries found in zip file:" << filename;
		zip_close(zipFile);
		return false;
	}

	for (int i = 0; i < numEntries; i++) {
		zip_file_t* file = zip_fopen_index(zipFile, i, 0);
		if (!file) {
			qWarning() << "Failed to open entry" << i << "in zip file:" << filename;
			zip_close(zipFile);
			return false;
		}

		QString destPath = target + "/" + zip_get_name(zipFile, i, 0);
		QFile dest(destPath);
		if (!dest.open(QIODevice::WriteOnly)) {
			qWarning() << "Failed to open target file for writing:" << destPath;
			zip_fclose(file);
			zip_close(zipFile);
			return false;
		}

		char buffer[ZIP_FILE_CACHE_SIZE];
		int bytesRead = 0;
		while ((bytesRead = zip_fread(file, buffer, ZIP_FILE_CACHE_SIZE)) > 0) {
			dest.write(buffer, bytesRead);
		}

		dest.close();
		zip_fclose(file);
	}

	zip_close(zipFile);
	qInfo() << "Successfully decompressed directory from:" << filename << "to target directory:" << target;
	return true;
}